#pragma once
#include "../common/net.hpp"
#include <future>
namespace qiangsir
{
    namespace client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using AsyncResponse = std::future<BaseMessage::ptr>;
            using RequestCallBack = std::function<void(const BaseMessage::ptr &)>;
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr _request;
                RType _rtype;
                std::promise<BaseMessage::ptr> _result;
                RequestCallBack _cb;
            };
            void onResponse(const BaseConnection::ptr &conn, BaseMessage::ptr &msg)
            {
                std::string rid = msg->id();
                auto rd = getDescribe(rid);
                if(rd.get() == nullptr)
                {
                    ELOG("收到响应，但未找到对应请求描述");
                    return;
                }
                RType rtype = rd->_rtype;
                if(rtype == RType::REQ_ASYNC)
                {
                    rd->_result.set_value(msg);
                }
                else if(rtype == RType::REQ_CALLBACK)
                {
                    rd->_cb(msg);
                }
                else{
                    ELOG("未知请求");
                }
                delDescribe(rid);
            }
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req,
                      BaseMessage::ptr &resp)
            {
                AsyncResponse rsp_future;
                bool ret = send(conn,req,rsp_future);
                if(ret == false)
                {
                    return false;
                }
                resp = rsp_future.get();
                return true;
            }
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req,
                      AsyncResponse &resp)
            {
                RequestDescribe::ptr  rdp = newDescribe(req,RType::REQ_ASYNC);
                if(rdp.get() == nullptr)
                {
                    ELOG("请求描述对象创建失败");
                    return false;
                }
                conn->send(req);
                resp = rdp->_result.get_future();
                return true;

            }
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req,
                      const RequestCallBack &callback)
            {
                RequestDescribe::ptr  rdp = newDescribe(req,RType::REQ_CALLBACK,callback);
                if(rdp.get() == nullptr)
                {
                    ELOG("请求描述对象创建失败");
                    return false;
                }
                conn->send(req);
                return true;
            }

        private:
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rtype,
                                             const RequestCallBack &cb = RequestCallBack())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr rd = std::make_shared<RequestDescribe>();
                rd->_request = req;
                rd->_rtype = rtype;
                if (rtype == RType::REQ_CALLBACK && cb)
                {
                    rd->_cb = cb;
                }
                _requestors.insert(std::make_pair(req->id(), rd));
                return rd;
            }
            RequestDescribe::ptr getDescribe(const std::string &id)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _requestors.find(id);
                if(it == _requestors.end())
                {
                    ELOG("未找到对应请求描述");
                    return RequestDescribe::ptr();
                }
                return it->second;
            }
            void delDescribe(const std::string &id)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _requestors.erase(id);
            }

        private:
            std::mutex _mutex;
            // rid<-->rd
            std::unordered_map<std::string, RequestDescribe::ptr> _requestors;
        };
    }
}